﻿using System;
using System.Collections;
using System.Collections.Generic;
using Assets.Scripts.Enums;
using UnityEngine;

namespace Assets.Scripts.UI
{
    public class UserInterface
    {
        public UserInterface()
        {
            var uiRoot = UiRoot.Get;
            uiRoot.KeyDown += ControlKeyDown;
            uiRoot.KeyUp += ControlKeyUp;
        }
        public List<Control> CurrentControls => _currentControls;

        public void Run<T>(object data) where T : Control, new()
        {
            SetScreen<T>(data);
        }
        public void Run<T>() where T : Control, new()
        {
            SetScreen<T>();
        }
        public void Close<T>()where T:Control
        {
            Type t = typeof(T);
            string pageName = t.ToString();

            if (_allControls != null && _allControls.ContainsKey(pageName))
            {
                Close(_allControls[pageName]);
            }
        }
        public void PopNode(Control control)
        {
            if (CheckIfNeedBack(control) == false)
                return;

            bool isFound = false;
            for (int i = 0; i < _currentControls.Count; i++)
            {
                if (_currentControls[i] == control)
                {
                    _currentControls.RemoveAt(i);
                    _currentControls.Add(control);
                    isFound = true;
                    break;
                }
            }

            if (!isFound)
                _currentControls.Add(control);

            HideOldNodes();
        }
        public void Close()
        {

            if (_currentControls == null || _currentControls.Count <= 1) return;

            Control closePage = _currentControls[_currentControls.Count - 1];
            _currentControls.RemoveAt(_currentControls.Count - 1);

            //show older page.
            if (_currentControls.Count > 0)
            {
                Control page = _currentControls[_currentControls.Count - 1];
                ShowScreen(page.Name, page, () =>
                {
                    closePage.Hide();
                });

            }
        }
        public IEnumerator Delay()
        {
            yield return new WaitForSeconds(0.1f);
        }

        private void Close(Control control)
        {
            if (control?.IsActive() == false && _currentControls!=null)
            {
                for (int i = 0; i < _currentControls.Count; i++)
                {
                    if (_currentControls[i] == control)
                    {
                        _currentControls.RemoveAt(i);
                        break;
                    }
                }
                return;
            }
            if (_currentControls != null && _currentControls.Count >= 1 &&
                _currentControls[_currentControls.Count - 1] == control)
            {
                _currentControls.RemoveAt(_currentControls.Count - 1);

                //show older page.
                if (_currentControls.Count > 0)
                {
                    Control page = _currentControls[_currentControls.Count - 1];

                    ShowScreen(page.Name, page);
                    control?.Hide();

                    return;
                }
            }
            else if (control != null && control.CheckIfNeedBack())
            {
                if (_currentControls != null)
                    for (int i = 0; i < _currentControls.Count; i++)
                    {
                        if (_currentControls[i] == control)
                        {
                            _currentControls.RemoveAt(i);
                            control.Hide();
                            break;
                        }
                    }
            }

            control?.Hide();
        }
        private void SetScreen<T>(object data = null, Action callBack = null) where T : Control, new()
        {
            string name = typeof(T).ToString();
            if (_allControls.ContainsKey(name))
            {
                ShowScreen(name, _allControls[name], callBack, data);
            }
            else
            {
                T instance = new T();
                ShowScreen(name, instance, callBack, data);
            }
        }
        private void ShowScreen(string name, Control instance, Action callback = null, object data = null)
        {
            Control control;
            if (_allControls.ContainsKey(name))
                control = _allControls[name];
            else
            {
                _allControls.Add(name, instance);
                control = instance;
            }

            control.Data = data;

            control.Init();
            control.Show(this);

            callback?.Invoke();
        }
        private void HideOldNodes()
        {
            if (_currentControls.Count < 1)
                return;
            Control topPage = _currentControls[_currentControls.Count - 1];
            if (topPage.UiMode == UiMode.HideOther)
            {
                for (int i = _currentControls.Count - 2; i >= 0; i--)
                {
                    if (_currentControls[i].IsActive())
                        _currentControls[i].Deactive();
                }
            }
        }
        private bool CheckIfNeedBack(Control control)
        {
            return control != null && control.CheckIfNeedBack();
        }
        private void ControlKeyDown(object sender, KeyEventArgs e)
        {
            KeyInfo info;
            if (ConvertToKeyInfo(e, out info))
            {
                info.Down = true;
                e.Handled = true;
                foreach (Control control in _currentControls)
                {
                    if (control is IInputHandler)
                        control.ScreenKeyPress(info);
                }
            }
        }
        private void ControlKeyUp(object sender, KeyEventArgs e)
        {
            KeyInfo info;
            if (ConvertToKeyInfo(e, out info))
            {
                info.Down = false;
                e.Handled = true;
                foreach (Control control in _currentControls)
                {
                    if (control is IInputHandler)
                        control.ScreenKeyPress(info);
                }
            }
        }
        private bool ConvertToKeyInfo(KeyEventArgs args, out KeyInfo info)
        {
            bool recognized = true;

            info = new KeyInfo();

            switch (args.KeyCode)
            {
                case Keys.Up:       info.Key = Key.Up; break;
                case Keys.Down:     info.Key = Key.Down; break;
                case Keys.Left:     info.Key = Key.Left; break;
                case Keys.Right:    info.Key = Key.Right; break;

                case Keys.A:        info.Key = Key.A; break;
                case Keys.B:        info.Key = Key.B; break;
                case Keys.C:        info.Key = Key.C; break;
                case Keys.D:        info.Key = Key.D; break;
                case Keys.E:        info.Key = Key.E; break;
                case Keys.F:        info.Key = Key.F; break;
                case Keys.G:        info.Key = Key.G; break;
                case Keys.H:        info.Key = Key.H; break;
                case Keys.I:        info.Key = Key.I; break;
                case Keys.J:        info.Key = Key.J; break;
                case Keys.K:        info.Key = Key.K; break;
                case Keys.L:        info.Key = Key.L; break;
                case Keys.M:        info.Key = Key.M; break;
                case Keys.N:        info.Key = Key.N; break;
                case Keys.O:        info.Key = Key.O; break;
                case Keys.P:        info.Key = Key.P; break;
                case Keys.Q:        info.Key = Key.Q; break;
                case Keys.R:        info.Key = Key.R; break;
                case Keys.S:        info.Key = Key.S; break;
                case Keys.T:        info.Key = Key.T; break;
                case Keys.U:        info.Key = Key.U; break;
                case Keys.V:        info.Key = Key.V; break;
                case Keys.W:        info.Key = Key.W; break;
                case Keys.X:        info.Key = Key.X; break;
                case Keys.Y:        info.Key = Key.Y; break;
                case Keys.Z:        info.Key = Key.Z; break;

                case Keys.D0:       info.Key = Key.Digit0; break;
                case Keys.D1:       info.Key = Key.Digit1; break;
                case Keys.D2:       info.Key = Key.Digit2; break;
                case Keys.D3:       info.Key = Key.Digit3; break;
                case Keys.D4:       info.Key = Key.Digit4; break;
                case Keys.D5:       info.Key = Key.Digit5; break;
                case Keys.D6:       info.Key = Key.Digit6; break;
                case Keys.D7:       info.Key = Key.Digit7; break;
                case Keys.D8:       info.Key = Key.Digit8; break;
                case Keys.D9:       info.Key = Key.Digit9; break;

                case Keys.Space:    info.Key = Key.Space; break;

                case Keys.Enter:    info.Key = Key.Enter; break;
                case Keys.Tab:      info.Key = Key.Tab; break;
                case Keys.Back:     info.Key = Key.Backspace; break;
                case Keys.Delete:   info.Key = Key.Delete; break;
                case Keys.Escape:   info.Key = Key.Escape; break;

                case Keys.OemSemicolon: info.Key = Key.Semicolon; break;
                case Keys.Oemcomma: info.Key = Key.Comma; break;
                case Keys.OemPeriod: info.Key = Key.Period; break;
                case Keys.OemQuestion: info.Key = Key.Slash; break;

                case Keys.F1: info.Key = Key.F1; break;
                case Keys.F2: info.Key = Key.F2; break;
                case Keys.F3: info.Key = Key.F3; break;
                case Keys.F4: info.Key = Key.F4; break;
                case Keys.F5: info.Key = Key.F5; break;
                case Keys.F6: info.Key = Key.F6; break;
                case Keys.F7: info.Key = Key.F7; break;
                case Keys.F8: info.Key = Key.F8; break;
                case Keys.F9: info.Key = Key.F9; break;
                case Keys.F10: info.Key = Key.F10; break;
                case Keys.F11: info.Key = Key.F11; break;
                case Keys.F12: info.Key = Key.F12; break;
                case Keys.F13: info.Key = Key.F13; break;
                case Keys.F14: info.Key = Key.F14; break;
                case Keys.F15: info.Key = Key.F15; break;
                case Keys.F16: info.Key = Key.F16; break;
                case Keys.F17: info.Key = Key.F17; break;
                case Keys.F18: info.Key = Key.F18; break;
                case Keys.F19: info.Key = Key.F19; break;
                case Keys.F20: info.Key = Key.F20; break;
                case Keys.F21: info.Key = Key.F21; break;
                case Keys.F22: info.Key = Key.F22; break;
                case Keys.F23: info.Key = Key.F23; break;
                case Keys.F24: info.Key = Key.F24; break;

                default: recognized = false; break;
            }

            info.Shift = args.Shift;
            info.Control = args.Control;

            return recognized;
        }

        private readonly List<Control> _currentControls = new List<Control>();
        private readonly Dictionary<string, Control> _allControls = new Dictionary<string, Control>();

        
    }

}
